~ chicken-core (master) /manual/Module (scheme lazy)
Trap1[[tags: manual]]2[[toc:]]34== Module (scheme lazy)567Delayed evaluation89<macro>(delay <expression>)</macro>1011Semantics: The delay construct is used together with the procedure force to12implement lazy evaluation or call by need. {{(delay <expression>)}} returns an13object called a promise which at some point in the future can be asked (by the14force procedure) to evaluate <expression>, and deliver the resulting value. The15effect of <expression> returning multiple values is unspecified.1617<macro>(delay-force <expression>)</macro>1819Semantics: The expression {{(delay-force expression)}} is conceptually similar to20{{(delay (force expression))}}, with the difference that forcing the result of delay-force will21in effect result in a tail call to {{(force expression)}}, while forcing the result of22{{(delay (force expression))}} might not. Thus iterative lazy algorithms that might result in a23long series of chains of delay and force can be rewritten using delay-force to24prevent consuming unbounded space during evaluation.2526<macro>(force promise)</macro>2728The force procedure forces the value of a29promise created by delay, delay-force, or make-promise.If no value has been30computed for the promise, then a value is computed and returned. The value of31the promise must be cached (or "memoized") so that if it is forced a second32time, the previously computed value is returned. Consequently, a delayed33expression is evaluated using the parameter values and exception handler of the34call to force which first requested its value. If35promise is not a promise, it may be returned unchanged.3637 (force (delay (+ 1 2))) ==> 338 (let ((p (delay (+ 1 2))))39 (list (force p) (force p))) ==> (3 3)4041 (define integers42 (letrec ((next43 (lambda (n)44 (delay (cons n (next (+ n 1)))))))45 (next 0)))46 (define head47 (lambda (stream) (car (force stream))))48 (define tail49 (lambda (stream) (cdr (force stream))))5051 (head (tail (tail integers))) ==> 25253The following example is a mechanical54transformation of a lazy stream-filtering algorithm into Scheme. Each call to a55constructor is wrapped in delay, and each argument passed to a deconstructor is56wrapped in force. The use of {{(delay-force ...)}} instead of {{(delay (force ...))}}57around the body of the procedure ensures that an ever-growing sequence of58pending promises does not exhaust available storage, because force will in59effect force such sequences iteratively.6061 (define (stream-filter p? s)62 (delay-force63 (if (null? (force s))64 (delay '())65 (let ((h (car (force s)))66 (t (cdr (force s))))67 (if (p? h)68 (delay (cons h (stream-filter p? t)))69 (stream-filter p? t))))))7071 (head (tail (tail (stream-filter odd? integers)))) ==> 57273The following examples are not intended to74illustrate good programming style, as delay, force, and delay-force are mainly75intended for programs written in the functional style. However, they do76illustrate the property that only one value is computed for a promise, no77matter how many times it is forced.7879 (define count 0)80 (define p81 (delay (begin (set! count (+ count 1))82 (if (> count x)83 count84 (force p)))))85 (define x 5)86 p ==> a promise87 (force p) ==> 688 p ==> a promise, still89 (begin (set! x 10)90 (force p)) ==> 69192Various extensions to this semantics of delay,93force and delay-force are supported in some implementations:9495* Calling force on an object that is not a promise may simply return the object.9697* It may be the case that there is no means by which a promise can be98 operationally distinguished from its forced value. That is, expressions99 like the following may evaluate to either #t or to #f, depending on the100 implementation:101102 (eqv? (delay 1) 1) ==> unspecified103 (pair? (delay (cons 1 2))) ==> unspecified104105* Implementations may implement “implicit forcing,” where the value of a106 promise is forced by procedures that operate only on arguments of a certain107 type, like cdr and *. However, procedures that operate uniformly on their108 arguments, like list, must not force them.109110 (+ (delay (* 3 7)) 13) ==> unspecified111 (car112 (list (delay (* 3 7)) 13)) ==> a promise113114<procedure>(promise? obj)</procedure>115116The promise? procedure returns #t if its argument is a promise, and #f117otherwise. Note that promises are not necessarily disjoint from other Scheme118types such as procedures.119120<procedure>(make-promise obj)</promise>121122The make-promise procedure returns a promise which, when forced, will return123obj. It is similar to delay, but does not delay its argument: it is a procedure124rather than syntax. If125obj is already a promise, it is returned.126127---128Previous: [[Module (scheme inexact)]]129130Next: [[Module (scheme load)]]